package top.pengdong.pictureShare.gateway.config.security;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

/**
 * @description:
 * JWT认证管理器，主要的作用就是对携带过来的token进行校验，比如过期时间，加密方式等
 * 一旦token校验通过，则交给鉴权管理器进行鉴权
 * @projectName: pictureShare
 * @see: top.pengdong.pictureShare.gateway.security
 * @author: pc
 * @createTime: 2022/4/18 14:31
 * @version: 1.0
 */
@Component
@Slf4j
public class JwtAuthenticationManager implements ReactiveAuthenticationManager {
	/**
	 * 使用JWT令牌进行解析令牌
	 */
	@Autowired
	private TokenStore tokenStore;

	@Override
	public Mono<Authentication> authenticate(Authentication authentication) {
		return Mono.justOrEmpty(authentication)
				.filter(a -> a instanceof BearerTokenAuthenticationToken)
				.cast(BearerTokenAuthenticationToken.class)
				.map(BearerTokenAuthenticationToken::getToken)
				.flatMap((accessToken -> {
					OAuth2AccessToken oAuth2AccessToken = this.tokenStore.readAccessToken(accessToken);
					//根据access_token从数据库获取不到OAuth2AccessToken
					if (oAuth2AccessToken == null) {
						return Mono.error(new InvalidTokenException("无效的token！"));
					} else if (oAuth2AccessToken.isExpired()) {
						return Mono.error(new InvalidTokenException("token已过期！"));
					}
					OAuth2Authentication oAuth2Authentication = this.tokenStore.readAuthentication(accessToken);
					if (oAuth2Authentication == null) {
						return Mono.error(new InvalidTokenException("无效的token！"));
					} else {
						return Mono.just(oAuth2Authentication);
					}
				})).cast(Authentication.class);
	}
}
